package com.empire.module.member.service.presentation;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.empire.framework.common.exception.util.ServiceExceptionUtil;
import com.empire.framework.common.pojo.PageResult;
import com.empire.framework.common.util.object.BeanUtils;
import com.empire.module.member.utils.WordUtil;
import com.empire.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.empire.framework.security.core.util.SecurityFrameworkUtils;
import com.empire.module.infra.api.file.FileApi;
import com.empire.module.member.controller.admin.presentation.vo.PresentationPageReqVO;
import com.empire.module.member.controller.admin.presentation.vo.PresentationSaveReqVO;
import com.empire.module.member.dal.dataobject.presentation.PresentationDO;
import com.empire.module.member.dal.mysql.presentation.PresentationMapper;
import com.empire.module.member.enums.ErrorCodeConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 报告 Service 实现类
 *
 * @author 主席大人
 */
@Slf4j
@Service
@Validated
public class PresentationServiceImpl extends ServiceImpl<PresentationMapper, PresentationDO> implements PresentationService {

    @Resource
    private PresentationMapper presentationMapper;
    @Resource
    private FileApi fileApi;

    @Override
    public Long createPresentation(PresentationSaveReqVO createReqVO) {
        // 获取当前登录用户ID
        Long createDeptId = SecurityFrameworkUtils.getLoginUserDeptId();

        // 转换为DO对象
        PresentationDO presentation = BeanUtils.toBean(createReqVO, PresentationDO.class);
        presentation.setCreateDeptId(createDeptId);
        presentation.setCreateDeptId(SecurityFrameworkUtils.getLoginUserDeptId());

        // 插入数据库
        presentationMapper.insert(presentation);
        return presentation.getId();
    }

    @Override
    public void updatePresentation(PresentationSaveReqVO updateReqVO) {
        // 校验存在
        validatePresentationExists(updateReqVO.getId());

        // 获取当前登录用户ID
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();

        // 转换为DO对象
        PresentationDO updateObj = BeanUtils.toBean(updateReqVO, PresentationDO.class);
        updateObj.setUpdater(loginUserId+"");

        // 更新数据库
        presentationMapper.updateById(updateObj);
    }

    @Override
    public void deletePresentation(Long id) {
        // 校验存在
        PresentationDO presentation = validatePresentationExists(id);

        // 删除物理文件
        deleteWordFile(presentation);

        // 删除数据库记录
        presentationMapper.deleteById(id);
    }

    /**
     * 删除报告对应的Word文件
     */
    private void deleteWordFile(PresentationDO presentation) {
        if (presentation.getWordFilePath() == null) {
            return;
        }

        File wordFile = new File(presentation.getWordFilePath());
        if (wordFile.exists() && wordFile.isFile()) {
            boolean delete = wordFile.delete();
            if (!delete) {
                // 日志记录：文件删除失败
                System.err.println("Failed to delete word file: " + wordFile.getAbsolutePath());
            }
        }
    }

    private PresentationDO validatePresentationExists(Long id) {
        PresentationDO presentation = presentationMapper.selectById(id);
        if (presentation == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PRESENTATION_NOT_EXISTS);
        }
        return presentation;
    }

    @Override
    public PresentationDO getPresentation(Long id) {
        return presentationMapper.selectById(id);
    }

    @Override
    public PageResult<PresentationDO> getPresentationPage(PresentationPageReqVO pageReqVO) {
        // 设置当前登录用户的部门ID
        pageReqVO.setCreateDeptId(SecurityFrameworkUtils.getLoginUserDeptId());
        return presentationMapper.selectPage(pageReqVO);
    }

    @Override
    public List<PresentationDO> getPresentationList() {
        // 设置当前登录用户的部门ID
        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        return presentationMapper.selectList(new LambdaQueryWrapperX<PresentationDO>()
                .likeIfPresent(PresentationDO::getCreateDeptId, String.valueOf(deptId)));
    }

    @Override
    public boolean mergeBinaryData(Long id, File htmlFile) {
        try {
            PresentationDO presentation = validatePresentationExists(id);
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();

            // 1. 将HTML文件转换为Word文件（先存储到临时文件）
            String tempFileName = presentation.getName() + "_" + System.currentTimeMillis() + ".docx";
            File tempWordFile = File.createTempFile("temp_", tempFileName);

            try {
                // 执行HTML到Word的转换
                WordUtil.htmlToWord(htmlFile, tempWordFile);

                // 2. 读取临时Word文件内容为字节数组
                byte[] content;
                try (FileInputStream fis = new FileInputStream(tempWordFile);
                     ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        bos.write(buffer, 0, len);
                    }
                    content = bos.toByteArray();
                }

                // 3. 构建文件存储路径（按用户ID和日期组织）
                String filePath = String.format("presentation/%d/%s",
                        loginUserId,
                        LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));

                // 4. 调用文件API保存文件
                String fileAccessPath = fileApi.createFile(tempFileName, filePath, content);

                // 5. 更新报告的文件信息
                presentation.setWordFilePath(fileAccessPath);
                presentation.setHasFile(true);
                presentation.setFileGenerateTime(LocalDateTime.now());
                presentation.setUpdater(loginUserId.toString());
                presentationMapper.updateById(presentation);

                return true;
            } finally {
                // 清理临时文件
                if (tempWordFile.exists() && !tempWordFile.delete()) {
                    // 记录临时文件删除失败的日志
                    log.warn("Failed to delete temporary word file: {}", tempWordFile.getAbsolutePath());
                }
            }
        } catch (Exception e) {
            log.error("Failed to generate and save presentation word file", e);
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PRESENTATION_FILE_GENERATE_FAIL, e.getMessage());
        }
    }

    @Override
    public void downloadFile(HttpServletResponse response, Long id) throws IOException {
        PresentationDO presentation = validatePresentationExists(id);

        // 校验文件是否存在
        if (!presentation.getHasFile() || presentation.getWordFilePath() == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PRESENTATION_FILE_NOT_EXISTS);
        }

        File wordFile = new File(presentation.getWordFilePath());
        if (!wordFile.exists() || !wordFile.isFile()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PRESENTATION_FILE_NOT_EXISTS);
        }

        // 设置响应头
        response.setHeader("content-disposition",
                "attachment;filename=" + new String(presentation.getName().getBytes("UTF-8"), "ISO8859-1") + ".docx");
        response.setContentType("application/octet-stream");

        // 写入响应流
        try (InputStream is = new FileInputStream(wordFile);
             OutputStream out = response.getOutputStream()) {

            byte[] buf = new byte[1024];
            int len;
            while ((len = is.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.PRESENTATION_FILE_DOWNLOAD_FAIL, e.getMessage());
        }
    }
}
